Spring Cloud 负载均衡

  |  


Spring Cloud Ribbon实现负载均衡

负载均衡

负载均衡在系统架构中是一个非常重要的角色,在前面大型网站架构学习总结中,可以看到,高可用,伸缩性,性能几个架构要素中,负载均衡都有着很重要的地位,是系统压力缓解,系统扩容的重要手段之一。

服务端负载

一般来说,我们讲的负载均衡都是讲服务端负载均衡(不论硬负载还是软负载),比较常见的通过Nginx反向代理来实现负载均衡,例如下面图中所示

1546179423387

客户端负载均衡

这次我们所用到的Ribbon其实就是一种客户端负载均衡,与服务端负载均衡不同的是,客户端负载均衡不是通过一个统一的均衡器(Nginx)去均衡的,而是每一个客户端都维护着各自的负载均衡实现,例如下图所示

1546179924437

优势与不足对比

  • 客户端负载均衡:优势主要体现在稳定性高,各个客户端的负载均衡互不影响,例如上面客户端负载均衡中客户端2的Ribbon出问题了,肯定不会影响客户端1的调用的。劣势就是相对的,升级维护成本高,每次要升级的时候,每个客户端的Ribbon都需要升级。
  • 服务端负载均衡:优势主要体现在统一维护成本低,例如上面的服务端负载均衡,只需要升级Nginx就可以了。劣势同样是相对的,一旦故障,影响大。上面服务端负载均衡中,只要Nginx出问题了,整个系统就不能正常访问了。

Spring Cloud整合Ribbon实现负载均衡

新建服务名为consumer2的Eureka Client(两个实例)

实例1

1
2
3
4
server.port=1115
spring.application.name=consumer2
eureka.instance.hostname=localhost1
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

实例2

1
2
3
4
server.port=1114
spring.application.name=consumer2
eureka.instance.hostname=localhost1
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

提供的服务接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RestController
public class HelloController {

private final Logger logger = Logger.getLogger(getClass());

@Autowired
private DiscoveryClient client;

@RequestMapping(value="/hello",method = RequestMethod.GET)
public String index(){
ServiceInstance instance = client.getLocalServiceInstance();
logger.info("/hello host:"+instance.getHost()+"server_id"+instance.getServiceId()+"端口:"+instance.getPort());
return "hello";
}


}

consumer2的两个实例已经准备好了,暴露出来的接口,访问会打印出各自对应的端口信息,接下来我们就通过Ribbon来测试负载均衡

新建名为consumer3的Ribbon Erueka Client工程

1
2
3
server.port=1116
spring.application.name=consumer3
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

Erueka Client导入Ribbon依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

引入Ribbon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaRibbonApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaRibbonApplication.class, args);
}


@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}

这里可以看到,就是在之前用到的RestTemplate对象加上@LoadBalanced注解就达到将Ribbon引入的目的了

测试负载均衡接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RestController
public class HelloController {

private final Logger logger = Logger.getLogger(getClass());

@Autowired
private DiscoveryClient client;

@Autowired
RestTemplate restTemplate;

@RequestMapping("/hello")
public String index(){
//在这里调用consumer2提供的接口
return restTemplate.getForEntity("http://consumer2/hello",String.class).getBody();
}


}
  1. 接下来我们分别启动consumer2的两个实例(对应实际中的两台服务器),以及一个包含Ribbon的comsumer3实例。启动完成后服务列表如下

1546181883854

  1. 访问http://localhost:1116/hello,我们通过浏览器访问5次

    consumer2 (1115)实例控制台输出信息

1
2
3
2018-12-30 23:00:17.557  INFO 11468 --- [nio-1115-exec-3] c.d.eureka_client1.HelloController       : /hello host:localhost1server_idconsumer2端口:1115
2018-12-30 23:00:22.898 INFO 11468 --- [nio-1115-exec-5] c.d.eureka_client1.HelloController : /hello host:localhost1server_idconsumer2端口:1115
2018-12-30 23:00:29.584 INFO 11468 --- [nio-1115-exec-7] c.d.eureka_client1.HelloController : /hello host:localhost1server_idconsumer2端口:1115

​ consumer2 (1114)实例控制台输出信息

1
2
2018-12-30 23:00:25.757  INFO 12652 --- [nio-1114-exec-3] c.d.eureka_client1.HelloController       : /hello host:localhost1server_idconsumer2端口:1114
2018-12-30 23:00:30.086 INFO 12652 --- [nio-1114-exec-4] c.d.eureka_client1.HelloController : /hello host:localhost1server_idconsumer2端口:1114

这里可以看到,consumer2 (1115)实例被访问了3次, consumer2 (1114)被访问了2次,由于我们没有配置访问策略,所以默认用的轮询策略,也就证明Ribbon起到负载均衡的作用了。

负载均衡策略

这里对上面说的策略补充一下,Ribbon中主要有以下几种策略

  • 随机规则:RandomRule 随机访问一个实例
  • 最可用规则:BestAvailableRule 根据性能,响应速度,空闲程度等计算
  • 轮询规则(Ribbon默认):RoundRobinRule 多个实例依次轮询访问
  • 重试实现:RetryRule 对内部定义的策略反复尝试

总结

Eureka 整合Ribbon后,通过RestTemplate以服务名访问的方式调用就能实现负载均衡,我们不需要关注各应用的ip、端口,这些信息Ribbon都能从Eureka Server的服务列表获取到,在此基础上,实现Ribbon还是挺方便的。

参考书籍《Redis 实战》

参考文章 Redis 基础数据结构

文章目录
  1. 1. Spring Cloud Ribbon实现负载均衡
    1. 1.1. 负载均衡
      1. 1.1.1. 服务端负载
      2. 1.1.2. 客户端负载均衡
      3. 1.1.3. 优势与不足对比
    2. 1.2. Spring Cloud整合Ribbon实现负载均衡
      1. 1.2.1. 新建服务名为consumer2的Eureka Client(两个实例)
        1. 1.2.1.1. 实例1
        2. 1.2.1.2. 实例2
        3. 1.2.1.3. 提供的服务接口
      2. 1.2.2. 新建名为consumer3的Ribbon Erueka Client工程
      3. 1.2.3. Erueka Client导入Ribbon依赖
      4. 1.2.4. 引入Ribbon
      5. 1.2.5. 测试负载均衡接口
    3. 1.3. 负载均衡策略
  2. 2. 总结
|
本站总访问量 载入天数...载入时分秒...